/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package tablut;
import java.awt.*;
import javax.swing.*;
import java.util.LinkedList;


public class ReglesTablut{

        final static int TAILLE = 9;

        // Temps maximum par joueur et par partie, en secondes....
        final static int TEMPSMAXIMUM = 10*60; // 10 minutes pour un match complet

        // constantes pour les pièces
        private final static int VIDE = 0;
        private final static int BLANC = 1;
        private final static int NOIR = 2;
        private final static int ROI = 3;

//      private final static int CASESPECIALE = 4;
        private final static int CASEINTERDITE = 5;
        private final static int CASETRONE = 6;
        private final static int CASESORTIE = 7;

        private final static int FINPARMOUVEMENTILLEGAL = 0;
//      private final static int FINPARDEPASSEMENTTEMPS = 2;
        private final static int FINNORMALE = 1;

        private LinkedList<int[][]> historique;

        // board
        private int placementPieces[][];
        private int typeCases[][];

        // has the game ended?
        private boolean jeuTermine = false;

        // who is the winner?
        private int winner = 0;

        // who moves next?
        private int joueurAJouer;

        private int roiCol;

        private int roiLig;

        private int toursSansPrise = 0;

        // applet game viewer
        static private AppletTablut vueDuJeu;
        static private JFrame f = null;
        static boolean APPLETGRAPHIQUE = true;

        public void setAppletGraphique(boolean t) {
                APPLETGRAPHIQUE = t;
        }

        public void printPlateau(){
                for(int i=0;i<TAILLE;i++) {
                        System.out.print("[INFO] Plateau : " + i + "|");
                        for(int j=0;j<TAILLE;j++)
                                if (placementPieces[i][j]> 0)
                                        System.out.print(placementPieces[i][j]);
                                else
                                        System.out.print(".");
                        System.out.println();
                }
                System.out.println("[INFO] Plateau :  |_________");
                System.out.print("[INFO] Plateau :   ");
                for(int j=0;j<TAILLE;j++)
                        System.out.print(j);
                System.out.println();
        }

        public ReglesTablut(boolean applet){
                APPLETGRAPHIQUE = applet;
                historique = new LinkedList<int[][]>();
                // Initialize the board and king position
                placementPieces = new int[TAILLE][TAILLE];
                typeCases = new int[TAILLE][TAILLE];
                roiLig = 4;
                roiCol = 4;

                for( int i = 0; i < TAILLE; i++ )
                        for( int j = 0; j < TAILLE; j++ ) {
                                placementPieces[i][j] = VIDE;
                                typeCases[i][j] = VIDE;
                        }


                // Les quatres cases des coins sont interdites, pour tout joueur
                // (sauf théoriquement pour le Roi, mais s'il peut s'y rendre,
                // il doit trouver un autre moyen de sortir !)
                typeCases[0][0] = CASEINTERDITE;
                typeCases[0][TAILLE-1] = CASEINTERDITE;
                typeCases[TAILLE-1][0] = CASEINTERDITE;
                typeCases[TAILLE-1][TAILLE-1] = CASEINTERDITE;


                typeCases[4][4] = CASETRONE;

                // On place les sorties possibles
                for(int i = 3; i< 6;  i++) {
                        typeCases[i][0] = CASESORTIE;
                        typeCases[0][i] = CASESORTIE;
                        typeCases[i][TAILLE-1] = CASESORTIE;
                        typeCases[TAILLE-1][i] = CASESORTIE;
                }


                // Une fois que le Roi aura quitté son trone,
                // Plus personne ne pourra aller en [4,4] (sauf lui)
                placementPieces[4][4] = ROI;

                // On place les attaquants sur les cotés
                for( int i = 3; i < 6; i++ ){
                        placementPieces[0][i] = NOIR;
                        placementPieces[TAILLE-1][i] = NOIR;
                        placementPieces[i][0] = NOIR;
                        placementPieces[i][TAILLE-1] = NOIR;
                }

                // Dernières pointes des attaquants
                placementPieces[4][1] = NOIR;
                placementPieces[1][4] = NOIR;
                placementPieces[TAILLE-2][4] = NOIR;
                placementPieces[4][TAILLE-2] = NOIR;


                // On place les défenseurs
                placementPieces[3][4] = BLANC;
                placementPieces[2][4] = BLANC;
                placementPieces[4][3] = BLANC;
                placementPieces[4][2] = BLANC;
                placementPieces[5][4] = BLANC;
                placementPieces[6][4] = BLANC;
                placementPieces[4][5] = BLANC;
                placementPieces[4][6] = BLANC;

                // Le premier joueur qui peut jouer est BLANC
                joueurAJouer = BLANC;

                // S'il le faut, on initialise l'applet graphique
                if(APPLETGRAPHIQUE){
                        f = new JFrame("Vue du jeu");
                        vueDuJeu = new AppletTablut();
                        vueDuJeu.buildUI(f.getContentPane());
                        f.setSize(new Dimension(350 ,255));
                        vueDuJeu.setMyFrame(f);
                        f.setVisible(true);
                        int[][] temp = new int[11][11];

                        for( int i = 0; i < 9; i++ )
                                for( int j = 0; j < 9; j++ )
                                        temp[i][j] = placementPieces[i][j];

                        vueDuJeu.addBoard( "Départ ", temp);
                        vueDuJeu.update(f.getGraphics(), f.getInsets());
                }

        }

        public int getTaille() {
                return TAILLE;
        }

        public int getTempsMaximum () {
                return TEMPSMAXIMUM;
        }

        public int getJoueur () {
                return joueurAJouer;
        }

        // Méthode pour vérifier comment et qui a perdu le match
        public void gameOver(int loser, int type) {
                jeuTermine = true;
                String strPerdant = "";
                if( loser == BLANC ){
                        winner = NOIR;
                        strPerdant = "Blanc";
                }
                else{
                        if( loser == NOIR ){
                                winner = BLANC;
                                strPerdant = "Noir";
                        }
                        else
                                winner = VIDE;
                }

                String reason = "";

                if( type == FINPARMOUVEMENTILLEGAL ) {// The player that lost did so by making an illegal move
                        System.out.println(strPerdant + " perd avec un coup illégal");
                        reason = "ILLEGAL-MOVE";
                } else if( type == FINNORMALE ) {// The game was played to the end and won properly
                                System.out.println( strPerdant + " perd suivant les règles.");
                                reason = "FAIR-PLAY";
                } else if( type == 2 ) {// mate
                                System.out.println( "Egalité" );
                                reason = "DEUCE";
                } else if (type == 10) {// timeout
                                System.out.println("Timeout");
                                reason = "TIMEOUT";
                } else {
                        System.out.println("Fin de type " + type);
                        reason = "UNKNOWN";
                }
                System.out.println("[ARBITRE] " + winner + " GAGNE. RAISON: " + reason);
        }

        public boolean getGameOver() {
                return jeuTermine;
        }

        public int getGagnant() {
                return winner;
        }

        private void ajouteHistorique(int[][] plateau){
                int[][] copie = new int[TAILLE][TAILLE];
                for(int i=0;i<TAILLE;i++)
                        for(int j=0;j<TAILLE;j++)
                                copie[i][j] = plateau[i][j];
                historique.add(copie);
        }

        private int compteHistorique(int[][] plateau) {
                int retvalue = 0;
                for(int[][] copies: historique){
                        boolean identique = true;
                        int i = 0;
                        while ((i < TAILLE) && (identique)) {
                                int j = 0;
                                while ((j< TAILLE) && (identique)) {
                                        if (copies[i][j] != plateau[i][j])
                                                identique = false;
                                        j++;
                                }
                                i++;
                        }
                        if (identique) retvalue ++;
                }
                return retvalue;
        }

        // Méthode permettant de faire un mouvement du joueur joueurAJouer
        public void executeMouvement(int departLigne, int departColonne,
                        int arriveeLigne, int arriveeColonne ){

                boolean capture = false;

                if ((departLigne == 0) && (departColonne == 0) &&
                                (arriveeLigne == 0) && (arriveeColonne == 0 ) ) { // Mouvement Nul
                        // Il faut vérifier qu'effectivement aucun mouvement n'est possible
                        // pour joueurAJouer
                        for(int i=0;i < TAILLE; i++)
                                for(int j=0; j< TAILLE; j++)
                                        if (placementPieces[i][j] == joueurAJouer)
                                                // Verifie si autour il n'y a aucune case vide
                                                if ( ((i>0) && (placementPieces[i-1][j] == VIDE) &&
                                                                (typeCases[i-1][j]!=CASETRONE) && (typeCases[i-1][j]!=CASEINTERDITE) )
                                                                || ((i<TAILLE-1) && (placementPieces[i+1][j] == VIDE) &&
                                                                                (typeCases[i+1][j]!=CASETRONE) && (typeCases[i+1][j]!=CASEINTERDITE) )
                                                                                || ((j>0) && (placementPieces[i][j-1] == VIDE) &&
                                                                                                (typeCases[i][j-1]!=CASETRONE) && (typeCases[i][j-1]!=CASEINTERDITE) )
                                                                                                || ((j<TAILLE-1) && (placementPieces[i][j+1] == VIDE) &&
                                                                                                                (typeCases[i][j+1]!=CASETRONE) && (typeCases[i][j+1]!=CASEINTERDITE) ) ) {
                                                        System.out.println("[ARBITRE] Mouvement nul alors qu'au moins un mouvement est encore possible.");
                                                        gameOver(joueurAJouer, FINPARMOUVEMENTILLEGAL);
                                                }
                }

                // Est-ce que la bonne couleur joue ?
                // Est-ce qu'on trouve la bonne couleur au départ ?
                // Est-ce que l'on bouge vraiment ?
                if( (joueurAJouer == NOIR && placementPieces[departLigne][departColonne] != joueurAJouer ) ||
                                (joueurAJouer == BLANC && ( placementPieces[departLigne][departColonne] != joueurAJouer &&
                                                placementPieces[departLigne][departColonne] != ROI )) ||
                                                (departLigne == arriveeLigne && departColonne == arriveeColonne) ){
                        System.out.println("[ARBITRE] La case de départ du mouvement n'est pas compatible avec le joueur.");
                        gameOver(joueurAJouer, FINPARMOUVEMENTILLEGAL);
                }

                // Si c'est une case interdite, personne ne peut y aller
                if((typeCases[arriveeLigne][arriveeColonne] == CASEINTERDITE) ||
                                (typeCases[arriveeLigne][arriveeColonne] == CASETRONE) ) {
                        System.out.println("[ARBITRE] La case d'arrivée du mouvement est une case interdite.");
                        gameOver(joueurAJouer, FINPARMOUVEMENTILLEGAL);
                }

                // Est-ce que le mouvement est bien horizontal ou vertical...
                if( departLigne == arriveeLigne || departColonne == arriveeColonne ){
                        if( departLigne == arriveeLigne ){ // Le long d'une ligne
                                // Vérifions qu'il n'y a pas de pièces le long de la trajectoire
                                int decal;
                                if (departColonne < arriveeColonne) decal = 1;
                                else decal = -1;
                                for(int i = departColonne+decal; i!= (arriveeColonne+decal); i+=decal) {
                                        if (placementPieces[departLigne][i] != VIDE ) {
                                                System.out.println("[ARBITRE] Il y a des pions sur la trajectoire du mouvement.");
                                                gameOver(joueurAJouer, FINPARMOUVEMENTILLEGAL);
                                        }
                                }
                        } else { // Le long d'une colonne
                                int decal;
                                if (departLigne < arriveeLigne) decal = 1;
                                else decal = -1;
                                for( int i = departLigne+decal; i != (arriveeLigne+decal); i+=decal ){
                                        if( placementPieces[i][departColonne] != VIDE ) {
                                                System.out.println("[ARBITRE] Il y a des pions sur la trajectoire du mouvement.");
                                                gameOver(joueurAJouer, FINPARMOUVEMENTILLEGAL);
                                        }
                                }
                        }
                }
                else{ // Mouvement Diagonal
                        System.out.println("[ARBITRE] La trajectoire n'est pas celle d'une tour.");
                        gameOver(joueurAJouer, FINPARMOUVEMENTILLEGAL);
                }


                int couleurPiece = placementPieces[departLigne][departColonne];

                placementPieces[arriveeLigne][arriveeColonne] = couleurPiece;
                placementPieces[departLigne][departColonne] = VIDE;

                if( couleurPiece == ROI ){
                        roiLig = arriveeLigne;
                        roiCol = arriveeColonne;
                }

                // Verification des deux cas de fin de partie
                if( (joueurAJouer == BLANC) &&
                                (couleurPiece == ROI) &&
                                (typeCases[arriveeLigne][arriveeColonne] == CASESORTIE)) { // Blanc a gagné
                        System.out.println("[ARBITRE] Le roi vient de sortir.");
                        gameOver(NOIR, FINNORMALE); // Blanc a gagné !!
                }
                else{ // Si Noir a joué, il peut y avoir la prise du Roi
                        if( //(typeCases[roiLig][roiCol] != CASETRONE) && Le roi peut être capturé sur son trone
                                        ((roiLig-1 >= 0 && ( placementPieces[roiLig-1][roiCol] == NOIR ||
                                                        typeCases[roiLig-1][roiCol] == CASETRONE )) ||
                                                        roiLig-1 < 0 ) &&
                                                        ((roiLig+1 < TAILLE && ( placementPieces[roiLig+1][roiCol] == NOIR ||
                                                                        typeCases[roiLig+1][roiCol] == CASETRONE)) ||
                                                                        roiLig+1 >= TAILLE ) &&
                                                                        ((roiCol-1 >= 0 && ( placementPieces[roiLig][roiCol-1] == NOIR ||
                                                                                        typeCases[roiLig][roiCol-1] == CASETRONE )) ||
                                                                                        roiCol-1 < 0 ) &&
                                                                                        ((roiCol+1 < TAILLE && ( placementPieces[roiLig][roiCol+1] == NOIR ||
                                                                                                        typeCases[roiLig][roiCol+1] == CASETRONE )) ||
                                                                                                        roiCol +1 >= TAILLE) ){
                                System.out.println("[ARBITRE] Les noirs viennent de capturer le roi.");
                                gameOver(BLANC, FINNORMALE); // Noir a capturé le Roi !!
                        }
                }

                if (joueurAJouer == BLANC) {// NOIR peut être pris entre BLANCs et ROI (le Roi est armé).
                        int nbcapture = 0;
                        if( ( arriveeLigne-2 >= 0 && placementPieces[arriveeLigne-1][arriveeColonne] == NOIR ) &&
                                        ( placementPieces[arriveeLigne-2][arriveeColonne] == BLANC ||
                                                        typeCases[arriveeLigne-2][arriveeColonne] == CASETRONE ||
                                                        placementPieces[arriveeLigne-2][arriveeColonne] == ROI)) {
                                placementPieces[arriveeLigne-1][arriveeColonne] = VIDE; nbcapture++; }
                        if( ( arriveeLigne+2 < TAILLE && placementPieces[arriveeLigne+1][arriveeColonne] == NOIR ) &&
                                        ( placementPieces[arriveeLigne+2][arriveeColonne] == BLANC ||
                                                        typeCases[arriveeLigne+2][arriveeColonne] == CASETRONE ||
                                                        placementPieces[arriveeLigne+2][arriveeColonne] == ROI)) {
                                placementPieces[arriveeLigne+1][arriveeColonne] = VIDE; nbcapture++; }
                        if( ( arriveeColonne-2 >= 0 && placementPieces[arriveeLigne][arriveeColonne-1] == NOIR ) &&
                                        ( placementPieces[arriveeLigne][arriveeColonne-2] == BLANC ||
                                                        typeCases[arriveeLigne][arriveeColonne-2] == CASETRONE ||
                                                        placementPieces[arriveeLigne][arriveeColonne-2] == ROI)) {
                                placementPieces[arriveeLigne][arriveeColonne-1] = VIDE; nbcapture++; }
                        if( ( arriveeColonne+2 < TAILLE && placementPieces[arriveeLigne][arriveeColonne+1] == NOIR ) &&
                                        ( placementPieces[arriveeLigne][arriveeColonne+2] == BLANC ||
                                                        typeCases[arriveeLigne][arriveeColonne+2] == CASETRONE ||
                                                        placementPieces[arriveeLigne][arriveeColonne+2] == ROI)) {
                                placementPieces[arriveeLigne][arriveeColonne+1] = VIDE; nbcapture++; }
                        if (nbcapture > 0) {
                                capture = true;
                                System.out.println("[ARBITRE] Blancs a capturé " + nbcapture + " pions.");
                        }
                } else { // couleur est noir. Pas la peine de vérifier que roi peut être pris (déjà fait)
                        int nbcapture = 0;
                        if( ( arriveeLigne-2 >= 0 && placementPieces[arriveeLigne-1][arriveeColonne] == BLANC ) &&
                                        ( placementPieces[arriveeLigne-2][arriveeColonne] == NOIR ||
                                                        typeCases[arriveeLigne-2][arriveeColonne] == CASETRONE)) {
                                placementPieces[arriveeLigne-1][arriveeColonne] = VIDE; nbcapture++; }
                        if( ( arriveeLigne+2 < TAILLE && placementPieces[arriveeLigne+1][arriveeColonne] == BLANC ) &&
                                        ( placementPieces[arriveeLigne+2][arriveeColonne] == NOIR ||
                                                        typeCases[arriveeLigne+2][arriveeColonne] == CASETRONE)) {
                                placementPieces[arriveeLigne+1][arriveeColonne] = VIDE; nbcapture++; }
                        if( ( arriveeColonne-2 >= 0 && placementPieces[arriveeLigne][arriveeColonne-1] == BLANC ) &&
                                        ( placementPieces[arriveeLigne][arriveeColonne-2] == NOIR ||
                                                        typeCases[arriveeLigne][arriveeColonne-2] == CASETRONE)) {
                                placementPieces[arriveeLigne][arriveeColonne-1] = VIDE; nbcapture++; }

                        if( ( arriveeColonne+2 < TAILLE && placementPieces[arriveeLigne][arriveeColonne+1] == BLANC ) &&
                                        ( placementPieces[arriveeLigne][arriveeColonne+2] == NOIR ||
                                                        typeCases[arriveeLigne][arriveeColonne+2] == CASETRONE)) {
                                placementPieces[arriveeLigne][arriveeColonne+1] = VIDE;  nbcapture++; }
                        if (nbcapture > 0) {
                                capture = true;
                                System.out.println("[ARBITRE] Noirs a capturé " + nbcapture + " pions.");
                        }
                }

                // Changement de tour
                if(joueurAJouer == BLANC)
                        joueurAJouer = NOIR;
                else
                        joueurAJouer = BLANC;

                // On mémorise le plateau
                ajouteHistorique(placementPieces);
                if (compteHistorique(placementPieces) > 10) { // On a deja vu ce plateau 10 fois
                        System.out.println("[ARBITRE] J'ai deja vu ce plateau de jeux plus de 10 fois... Je ne fais rien mais bon...");
                }
                if (capture)
                        toursSansPrise = 0;
                else {
                        toursSansPrise++;
                        if (toursSansPrise > 30) {
                                System.out.println("[ARBITRE] 30 tours sans prises... EGALITE !");
                                gameOver(0,2);
                        }
                }

                // Update the applet
                if(APPLETGRAPHIQUE){
                        int[][] tempArray = new int[TAILLE][TAILLE];
                        for( int i = 0; i < 9; i++ )
                                for( int j = 0; j < 9; j++ )
                                        tempArray[i][j] = placementPieces[i][j];

                        vueDuJeu.addBoard((departLigne) + "x" + (departColonne) + " " + (arriveeLigne) + "x" +
                                        (arriveeColonne), tempArray );

                        vueDuJeu.update(f.getGraphics(), f.getInsets());
                }

        }

}
